<!--
 * @Author: yanjikun
 * @Date: 2022-04-14 10:51:21
 * @LastEditors: yanjikun
 * @LastEditTime: 2022-04-14 15:47:03
 * @Description: file content
-->
<template>
  <Select
    v-bind="getProps"
    :options="getOptions"
    @dropdown-visible-change="handleFetch"
    @change="handleChange"
  >
    <template v-for="item in Object.keys($slots)" #[item]="data">
      <slot :name="item" v-bind="data || {}"></slot>
    </template>
    <template v-if="loading" #suffixIcon>
      <LoadingOutlined spin />
    </template>
    <template v-if="loading" #notFoundContent>
      <span>
        <LoadingOutlined spin class="mr-1" />
        请等待数据加载完成...
      </span>
    </template>
  </Select>
</template>

<script setup lang="ts">
import { computed, ref, unref, watch, watchEffect } from 'vue'
import { Select } from 'ant-design-vue'
import { LoadingOutlined } from '@ant-design/icons-vue'
import { omit } from 'lodash'
import { isArray, isFunction } from '@/utils/is'
import { apiSelectProps } from '../types/components'
type OptionsItem = { label: string; value: string | number; disable?: boolean }
defineOptions({
  name: 'ApiSelect'
})
const props = defineProps(apiSelectProps)
const emit = defineEmits(['options-change', 'change'])
const options = ref<OptionsItem[]>([])
const loading = ref(false)
const isFirstLoad = ref(true)
const emitData = ref<any[]>([])
const getProps = computed(() => props as Recordable)
const getOptions = computed(() => {
  const { labelField, valueField, numberToString } = props
  return unref(options).reduce((prev, item: Recordable) => {
    if (item) {
      const value = item[valueField]
      prev.push({
        ...omit(item, [valueField, labelField]),
        label: item[labelField],
        value: numberToString ? `${value}` : value
      })
    }
    return prev
  }, [] as OptionsItem[])
})
const fetch = async () => {
  const api = props.api
  if (!api || !isFunction(api)) return
  options.value = []
  try {
    loading.value = true
    const data = await api(props.params)
    if (isArray(data)) {
      options.value = data
      emitChange()
      return
    }
    if (props.resultField) {
      options.value = data?.[props.resultField] ?? []
    }
    emitChange()
  } catch (error) {
    console.warn(error)
  } finally {
    loading.value = false
  }
}
const handleFetch = async (visible) => {
  if (!visible) return
  if (props.alwaysLoad) {
    await fetch()
  } else if (!props.immediate && unref(isFirstLoad)) {
    await fetch()
    isFirstLoad.value = false
  }
}
const emitChange = () => {
  emit('options-change', unref(getOptions))
}
const handleChange = (_, ...args) => {
  emitData.value = args
}
watchEffect(() => {
  props.immediate && !props.alwaysLoad && fetch()
})
watch(
  () => props.params,
  () => {
    !unref(isFirstLoad) && fetch()
  },
  { deep: true }
)
</script>

<style scoped></style>
